// Copyright 2013 Petar Maymounkov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package shutter

import (
	"bytes"
	"fmt"
	"reflect"
	"runtime"
	"runtime/pprof"
	"strconv"

	"circuit/kit/rh"
	"circuit/kit/rh/ns"
)

type dbg struct{}

func NewDbg() rh.FID {
	return ns.NewFID("dbg", dbg{})
}

func (dbg) Numcpu() rh.FID {
	return ns.NewStringFID(func() string {
		return strconv.Itoa(runtime.NumCPU())
	})
}

func (dbg) Numgoroutine() rh.FID {
	return ns.NewStringFID(func() string {
		return strconv.Itoa(runtime.NumGoroutine())
	})
}

func (dbg) Mem() rh.FID {
	return ns.NewStringFID(func() string {
		var m runtime.MemStats
		runtime.ReadMemStats(&m)
		return printStruct(m)
	})
}

func (dbg) Goroutine() rh.FID {
	return ns.NewStringFID(func() string {
		var w bytes.Buffer
		pprof.Lookup("goroutine").WriteTo(&w, 1)
		return w.String()
	})
}

func (dbg) Block() rh.FID {
	return ns.NewStringFID(func() string {
		var w bytes.Buffer
		pprof.Lookup("block").WriteTo(&w, 1)
		return w.String()
	})
}

func printStruct(i interface{}) string {
	var v = reflect.ValueOf(i)
	var t = reflect.TypeOf(i)
	var w bytes.Buffer
	for j := 0; j < t.NumField(); j++ {
		var f = t.Field(j)
		switch f.Type.Kind() {
		case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
			reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
			//
			fmt.Fprintf(&w, "%s: %v\n", f.Name, v.Field(j).Interface())
		default: //Array, Chan, Func, Interface, Map, Ptr, Slice, String, Struct, UnsafePointer
			fmt.Fprintf(&w, "%s: (skipping)\n", f.Name)
		}
	}
	return w.String()
}
